home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Newswatcher 2.0b22 / NW Source / Source / windutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-18  |  14.6 KB  |  534 lines  |  [TEXT/MMCC]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     windutil.c
  4.  
  5.     This reusable module contains miscellaneous window management 
  6.     utility routines.
  7.     
  8.     Copyright © 1994, Northwestern University.
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include <GestaltEqu.h>
  13.  
  14. #include "def.h"
  15. #include "windutil.h"
  16. #include "drawutil.h"
  17. #include "memutil.h"
  18.  
  19.  
  20.  
  21. typedef struct TWindowRecordStorage {
  22.     CWindowRecord storage;                    /* window record storage */
  23.     Boolean fromFreeList;                    /* true if storage obtained from free list */
  24.     struct TWindowRecordStorage *next;        /* pointer to next available free buffer */
  25. } TWindowRecordStorage;
  26.  
  27.  
  28.  
  29. static TWindowRecordStorage *freeWindowRecordStorage = nil;    /* pointer to first free buffer */
  30. static DeviceLoopDrawingUPP gGetDominantScreenOneDeviceUPP = nil;
  31.  
  32.  
  33.  
  34. /*----------------------------------------------------------------------------
  35.     MyFrontWindow 
  36.     
  37.     Get the frontmost window which belongs to the application.
  38.     
  39.     Exit:    function result = pointer to window record, or nil if none.
  40. ----------------------------------------------------------------------------*/
  41.  
  42. WindowPtr MyFrontWindow (void)
  43. {
  44.     WindowPeek windPeek;
  45.     
  46.     windPeek = (WindowPeek)FrontWindow();
  47.     while (windPeek != nil && windPeek->windowKind < 0) 
  48.         windPeek = windPeek->nextWindow;
  49.     return (WindowPtr)windPeek;
  50. }
  51.  
  52.  
  53.  
  54. /*----------------------------------------------------------------------------
  55.     InitializeWindowRecordStorage
  56.     
  57.     Preallocate window record storage buffers in high memory.
  58.     
  59.     Entry:    maxWindows = number of buffers to allocate.
  60.     
  61.     Exit:    function result = error code.
  62. ----------------------------------------------------------------------------*/
  63.  
  64. OSErr InitializeWindowRecordStorage (short maxWindows)
  65. {
  66.     short i;
  67.     Handle h;
  68.     TWindowRecordStorage **storage;
  69.     OSErr err = noErr;
  70.     
  71.     for (i = 0; i < maxWindows; i++) {
  72.         err = MyNewHandle(sizeof(TWindowRecordStorage), &h);
  73.         if (err != noErr) return err;
  74.         MyHLockHi(h);
  75.         storage = (TWindowRecordStorage**)h;
  76.         (**storage).next = freeWindowRecordStorage;
  77.         (**storage).fromFreeList = true;
  78.         freeWindowRecordStorage = *storage;
  79.     }
  80.     return noErr;
  81. }
  82.  
  83.  
  84.  
  85. /*----------------------------------------------------------------------------
  86.     MyNewWindow
  87.     
  88.     Create a new window. The window is a color window if we have color QD,
  89.     otherwise it's a black and white window.
  90.     
  91.     Entry:    rBounds = bounding rectangle in global coordinates.
  92.             title = Pascal format window title string.
  93.             visFlag = true to draw window, false to not draw window.
  94.             wDefProcID = window definition ID.
  95.             behind = -1 if in front, nil if in back, else pointer to window
  96.                 behind which this one will be placed.
  97.             goAwayFlag = true if window has close box.
  98.             refCon = application-defined reference.
  99.     
  100.     Exit:    function result = error code.
  101.             *wind = pointer to new window.
  102. ----------------------------------------------------------------------------*/
  103.  
  104. OSErr MyNewWindow (Rect *rBounds, Str255 title, Boolean visFlag, short wDefProcID,
  105.     WindowPtr behind, Boolean goAwayFlag, long refCon, WindowPtr *wind)
  106. {
  107.     TWindowRecordStorage *storage;
  108.     OSErr err = noErr;
  109.         
  110.     storage = freeWindowRecordStorage;
  111.     if (storage == nil) {
  112.         err = MyNewPtr(sizeof(TWindowRecordStorage), &storage);
  113.         if (err != noErr) return err;
  114.         storage->fromFreeList = false;
  115.     } else {
  116.         freeWindowRecordStorage = storage->next;
  117.     }
  118.     if (HasColorQD()) {
  119.         *wind = NewCWindow((CWindowRecord*)storage, rBounds, title, visFlag,
  120.             wDefProcID, behind, goAwayFlag, refCon);
  121.     } else {
  122.         *wind = NewWindow((CWindowRecord*)storage, rBounds, title, visFlag,
  123.             wDefProcID, behind, goAwayFlag, refCon);
  124.     }
  125.     
  126.     return noErr;
  127. }
  128.  
  129.  
  130.  
  131. /*----------------------------------------------------------------------------
  132.     MyDisposeWindow
  133.     
  134.     Dispose a window.
  135.     
  136.     Entry:    wind = pointer to window.
  137. ----------------------------------------------------------------------------*/
  138.  
  139. void MyDisposeWindow (WindowPtr wind)
  140. {
  141.     TWindowRecordStorage *storage;
  142.     
  143.     if (wind == nil) return;
  144.     storage = (TWindowRecordStorage*)wind;
  145.     CloseWindow(wind);
  146.     if (storage->fromFreeList) {
  147.         storage->next = freeWindowRecordStorage;
  148.         freeWindowRecordStorage = storage;
  149.     } else {
  150.         MyDisposePtr(storage);
  151.     }
  152. }
  153.  
  154.  
  155.  
  156. /*----------------------------------------------------------------------------
  157.     IsDAWindow 
  158.     
  159.     Check to see if a window belongs to a desk accessory.
  160.             
  161.     Entry:    wind = pointer to window.
  162.     
  163.     Exit:    function result = true if window belongs to a DA.
  164. ----------------------------------------------------------------------------*/
  165.  
  166. Boolean IsDAWindow (WindowPtr wind)
  167. {
  168.     if (wind == nil) {
  169.         return false;
  170.     } else {
  171.         return ((WindowPeek)wind)->windowKind < 0;
  172.     }
  173. }
  174.  
  175.  
  176.  
  177. /*----------------------------------------------------------------------------
  178.     GetWindRegionRects
  179.     
  180.     Return the bounding rects of a window's content and structure regions.
  181.     
  182.     Entry:    wind = pointer to window.
  183.     
  184.     Exit:    contRect = content region bounding rect.
  185.             strucRect = structure region bounding rect.
  186.                 
  187.     Adapted from Dean Yu's code in Develop #17.
  188. ----------------------------------------------------------------------------*/
  189.  
  190. void GetWindRegionRects (WindowPtr wind, Rect *contRect, Rect *strucRect)
  191. {
  192.     GrafPtr port;
  193.     RgnHandle contRgn, strucRgn;
  194.     Rect portRect, userState, stdState;
  195.     WStateData **wState;
  196.     
  197.     GetPort(&port);
  198.     SetPort(wind);
  199.     wState = (WStateData**)((WindowPeek)wind)->dataHandle;
  200.     userState = (**wState).userState;
  201.     stdState = (**wState).stdState;
  202.     if (((WindowPeek)wind)->visible) {
  203.         contRgn = ((WindowPeek)wind)->contRgn;
  204.         strucRgn = ((WindowPeek)wind)->strucRgn;
  205.         *contRect = (**contRgn).rgnBBox;
  206.         *strucRect = (**strucRgn).rgnBBox;
  207.     } else {
  208.         portRect = wind->portRect;
  209.         LocalToGlobalRect(&portRect);
  210.         MoveWindow(wind, -0x4000, -0x4000, false);
  211.         ShowHide(wind, true);
  212.         contRgn = ((WindowPeek)wind)->contRgn;
  213.         strucRgn = ((WindowPeek)wind)->strucRgn;
  214.         *contRect = (**contRgn).rgnBBox;
  215.         *strucRect = (**strucRgn).rgnBBox;
  216.         OffsetRect(contRect, portRect.left + 0x4000, portRect.top + 0x4000);
  217.         OffsetRect(strucRect, portRect.left + 0x4000, portRect.top + 0x4000);
  218.         ShowHide(wind, false);
  219.         MoveWindow(wind, portRect.left, portRect.top, false);
  220.     }
  221.     (**wState).userState = userState;
  222.     (**wState).stdState = stdState;
  223.     SetPort(port);
  224. }
  225.  
  226.  
  227.  
  228. /*----------------------------------------------------------------------------
  229.     GetDominantScreen
  230.     
  231.     Return the screen with the maximum intersection with a window.
  232.     
  233.     Entry:    wind = pointer to window.
  234.     
  235.     Exit:    screenRect = dominant screen's rectangle.
  236.             mainScreen = true if main screen (with menu bar).
  237.             onOneScreen = true if window completely contained on one screen.
  238.                 
  239.     Adapted from Dean Yu's code in Develop #17.
  240. ----------------------------------------------------------------------------*/
  241.  
  242. typedef struct TGetDominantScreenUserData {
  243.     GDHandle mainDevice;
  244.     GDHandle maxDevice;
  245.     long maxArea;
  246.     Rect windBounds;
  247. } TGetDominantScreenUserData;
  248.  
  249. static pascal void GetDominantScreenOneDevice (short depth, short deviceFlags,
  250.     GDHandle targetDevice, long userData)
  251. {
  252.     TGetDominantScreenUserData *ud;
  253.     Rect r, deviceRect;
  254.     long area;
  255.     
  256.     ud = (TGetDominantScreenUserData*)userData;
  257.     deviceRect = (**targetDevice).gdRect;
  258.     if (targetDevice == ud->mainDevice) deviceRect.top += GetMBarHeight();
  259.     SectRect(&ud->windBounds, &deviceRect, &r);
  260.     OffsetRect(&r, -r.left, -r.top);
  261.     area = (long)r.right * (long)r.bottom;
  262.     if (area > ud->maxArea) {
  263.         ud->maxArea = area;
  264.         ud->maxDevice = targetDevice;
  265.     }
  266. }
  267.  
  268. void GetDominantScreen (WindowPtr wind, Rect *screenRect, Boolean *mainScreen,
  269.     Boolean *onOneScreen)
  270. {
  271.     GrafPtr port;
  272.     RgnHandle rgn;
  273.     Rect contRect, strucRect, deviceLoopRect;
  274.     TGetDominantScreenUserData ud;
  275.     
  276.     if (wind == nil) {
  277.         if (!HasColorQD()) {
  278.             *screenRect = qd.screenBits.bounds;
  279.         } else {
  280.             ud.mainDevice = GetMainDevice();
  281.             *screenRect = (**ud.mainDevice).gdRect;
  282.         }
  283.         *mainScreen = true;
  284.         *onOneScreen = true;
  285.         return;
  286.     }
  287.         
  288.     GetPort(&port);
  289.     SetPort(wind);
  290.     GetWindRegionRects(wind, &contRect, &strucRect);
  291.     if (!HasColorQD()) {
  292.         *screenRect = qd.screenBits.bounds;
  293.         *mainScreen = true;
  294.         goto exit;
  295.     }
  296.     ud.mainDevice = GetMainDevice();
  297.     ud.maxDevice = ud.mainDevice;
  298.     ud.maxArea = 0;
  299.     rgn = NewRgn();
  300.     SectRgn(GetGrayRgn(), ((WindowPeek)wind)->contRgn, rgn);
  301.     if (EmptyRgn(rgn)) {
  302.         ud.windBounds = strucRect;
  303.     } else {
  304.         ud.windBounds = contRect;
  305.     }
  306.     deviceLoopRect = ud.windBounds;
  307.     GlobalToLocalRect(&deviceLoopRect);
  308.     RectRgn(rgn, &deviceLoopRect);
  309.     DeviceLoop(rgn, gGetDominantScreenOneDeviceUPP, (long)&ud, singleDevices);
  310.     DisposeRgn(rgn);
  311.     *screenRect = (**ud.maxDevice).gdRect;
  312.     *mainScreen = ud.maxDevice == ud.mainDevice;
  313.     
  314. exit:
  315.  
  316.     if (*mainScreen) strucRect.top -= GetMBarHeight();
  317.     *onOneScreen = strucRect.top >= screenRect->top && 
  318.         strucRect.bottom <= screenRect->bottom &&
  319.         strucRect.left >= screenRect->left &&
  320.         strucRect.right <= screenRect->right;
  321.     SetPort(port);
  322. }
  323.  
  324.  
  325.  
  326. /*----------------------------------------------------------------------------
  327.     WindOnScreen
  328.     
  329.     Check to see if a window is completely within a single screen.
  330.     
  331.     Entry:    wind = pointer to window.
  332.     
  333.     Exit:    function result = true if window is completely within a
  334.                 single screen.
  335. ----------------------------------------------------------------------------*/
  336.  
  337. Boolean WindOnScreen (WindowPtr wind)
  338. {
  339.     Rect screenRect;
  340.     Boolean mainScreen, onOneScreen;
  341.     
  342.     GetDominantScreen(wind, &screenRect, &mainScreen, &onOneScreen);
  343.     return onOneScreen;
  344. }
  345.  
  346.  
  347.  
  348. /*----------------------------------------------------------------------------
  349.     StaggerWindow
  350.     
  351.     Stagger a new window.
  352.     
  353.     Entry:    wind = pointer to window.
  354.             width = window width.
  355.             height = window height.
  356.             offsetFrom = pointer to window from which this window should be
  357.                 offset, or nil if none.
  358.             dontCoverFinderIcons = true to avoid covering up Finder icons.
  359. ----------------------------------------------------------------------------*/
  360.  
  361. void StaggerWindow (WindowPtr wind, short width, short height, WindowPtr offsetFrom,
  362.     Boolean dontCoverFinderIcons)
  363. {
  364.     Rect screenRect, r, contRect, strucRect;
  365.     WStateData **wState;
  366.     GrafPtr port;
  367.     Boolean mainScreen, onOneScreen, topLeft = false;
  368.  
  369.     GetPort(&port);
  370.     SetPort(wind);
  371.     SizeWindow(wind, width, height, false);
  372.     GetWindRegionRects(wind, &contRect, &strucRect);
  373.     GetDominantScreen(offsetFrom, &screenRect, &mainScreen, &onOneScreen);
  374.     if (mainScreen) {
  375.         screenRect.top += GetMBarHeight();
  376.     }
  377.     if (offsetFrom == nil) {
  378.         topLeft = true;
  379.     } else {
  380.         r = offsetFrom->portRect;
  381.         SetPort(offsetFrom);
  382.         LocalToGlobalRect(&r);
  383.         SetPort(wind);
  384.         MoveWindow(wind, r.left + 20, r.top + 20, false);
  385.         if (!WindOnScreen(wind)) {
  386.             topLeft = true;
  387.         } else if (dontCoverFinderIcons && mainScreen && 
  388.             screenRect.right - screenRect.left > 576) 
  389.         {
  390.             r = wind->portRect;
  391.             LocalToGlobalRect(&r);
  392.             if (r.right + 64 > screenRect.right) topLeft = true;
  393.         }
  394.     }
  395.     if (topLeft) {
  396.         MoveWindow(wind,
  397.             screenRect.left + contRect.left - strucRect.left + 4,
  398.             screenRect.top + contRect.top - strucRect.top + 4,
  399.             false);
  400.     }
  401.     
  402.     wState = (WStateData**)((WindowPeek)wind)->dataHandle;
  403.     r = wind->portRect;
  404.     LocalToGlobalRect(&r);
  405.     (**wState).userState = r;
  406.     SetPort(port);
  407. }
  408.  
  409.  
  410.  
  411. /*----------------------------------------------------------------------------
  412.     CalculateZoomRect
  413.     
  414.     Calculate the zoomed rectangle for a window.
  415.     
  416.     Entry:    wind = pointer to window.
  417.             width = desired width of zoomed window if infinite screen.
  418.             height = desired height of zoomed window if infinite screen.
  419.             dontCoverFinderIcons = true to avoid covering up Finder icons.
  420.     
  421.     Exit:    *zoomRect = zoomed rectangle for the window.
  422. ----------------------------------------------------------------------------*/
  423.  
  424. void CalculateZoomRect (WindowPtr wind, short width, short height, 
  425.     Rect *zoomRect, Boolean dontCoverFinderIcons)
  426. {
  427.     Rect windRect, screenRect, contRect, strucRect;
  428.     short leftDiff, topDiff, rightDiff, bottomDiff;
  429.     short screenWidth, screenHeight;
  430.     Boolean mainScreen, onOneScreen;
  431.  
  432.     GetDominantScreen(wind, &screenRect, &mainScreen, &onOneScreen);
  433.     GetWindRegionRects(wind, &contRect, &strucRect);
  434.     leftDiff = contRect.left - strucRect.left;
  435.     topDiff = contRect.top - strucRect.top;
  436.     rightDiff = strucRect.right - contRect.right;
  437.     bottomDiff = strucRect.bottom - contRect.bottom;
  438.     
  439.     if (mainScreen) {
  440.         screenRect.top += GetMBarHeight();
  441.         if (dontCoverFinderIcons && screenRect.right - screenRect.left > 576) 
  442.             screenRect.right -= 64;
  443.     }
  444.     InsetRect(&screenRect, 4, 4);
  445.     
  446.     width += leftDiff + rightDiff;
  447.     if (height < 0x7000) height += topDiff + bottomDiff;
  448.     screenWidth = screenRect.right - screenRect.left;
  449.     screenHeight = screenRect.bottom - screenRect.top;
  450.     if (width > screenWidth) width = screenWidth;
  451.     if (height > screenHeight) height = screenHeight;
  452.  
  453.     windRect = wind->portRect;
  454.     LocalToGlobalRect(&windRect);
  455.     windRect.left -= leftDiff;
  456.     windRect.top -= topDiff;
  457.     windRect.right = windRect.left + width;
  458.     windRect.bottom = windRect.top + height;
  459.     
  460.     if (windRect.left < screenRect.left)
  461.         OffsetRect(&windRect, screenRect.left - windRect.left, 0);
  462.     if (windRect.right > screenRect.right) 
  463.         OffsetRect(&windRect, screenRect.right - windRect.right, 0);
  464.     if (windRect.top < screenRect.top)
  465.         OffsetRect(&windRect, 0, screenRect.top - windRect.top);
  466.     if (windRect.bottom > screenRect.bottom)
  467.         OffsetRect(&windRect, 0, screenRect.bottom - windRect.bottom);
  468.         
  469.     windRect.left += leftDiff;
  470.     windRect.top += topDiff;
  471.     windRect.right -= rightDiff;
  472.     windRect.bottom -= bottomDiff;
  473.         
  474.     *zoomRect = windRect;
  475. }
  476.  
  477.  
  478.  
  479. /*----------------------------------------------------------------------------
  480.     WindRectEqualRect 
  481.     
  482.     Check to see if a window's rectangle equals a rectangle.
  483.             
  484.     Entry:    wind = pointer to window.
  485.             r = pointer to rectangle in global coords.
  486.             
  487.     Exit:    function result = true if window's rectangle is equal to
  488.                 the specified global rectange.
  489. ----------------------------------------------------------------------------*/
  490.  
  491. Boolean WindRectEqualRect (WindowPtr wind, Rect *r)
  492. {
  493.     GrafPtr port;
  494.     Rect windRect;
  495.     
  496.     GetPort(&port);
  497.     windRect = wind->portRect;
  498.     SetPort(wind);
  499.     LocalToGlobalRect(&windRect);
  500.     SetPort(port);
  501.     return EqualRect(&windRect, r);
  502. }
  503.  
  504.  
  505.  
  506. /*----------------------------------------------------------------------------
  507.     SetWindowNeedsZooming 
  508.     
  509.     Set a window standard state to (0,0,0,0) to force a zoom out on the next
  510.     zoom.
  511.             
  512.     Entry:    wind = pointer to window.
  513. ----------------------------------------------------------------------------*/
  514.  
  515. void SetWindowNeedsZooming (WindowPtr wind)
  516. {
  517.     WStateData **wState;
  518.     
  519.     wState = (WStateData**)((WindowPeek)wind)->dataHandle;
  520.     SetRect(&(**wState).stdState, 0, 0, 0, 0);
  521. }
  522.  
  523.  
  524.  
  525. /*----------------------------------------------------------------------------
  526.     windutil_InitUPP
  527.     
  528.     Initialize UPPs.
  529. ----------------------------------------------------------------------------*/
  530.  
  531. void windutil_InitUPP (void)
  532. {
  533.     gGetDominantScreenOneDeviceUPP = NewDeviceLoopDrawingProc(GetDominantScreenOneDevice);
  534. }